#!/bin/sh
# Copyright (C) 2024-2025 KoudaiPC Computer Technologies Co., Ltd.
# script name: huangdi-setup-environment.sh
# author: david921518@qq.com

. /usr/lib/kpc/posix-arrays.sh

################
# global vars
GLB_WORK_DIR=
GLB_DONE_FILE=
GLB_ROOT_DEV=
GLB_ROOT_PART=
GLB_ROOT_DISK=
GLB_ROOT_PART_NUM=
GLB_REBOOT_COUNTER=
#GLB_INSTALLED_PKGS=()
declare_i_arr GLB_INSTALLED_PKGS
GLB_NUM_INSTALLED_PKGS=0
GLB_REAL_PATH=
################

whoami=$(which whoami)
if [ x"$whoami" == x ]; then
  user="$USER"
else
  user=$(whoami)
fi

log_kmsg_path="/dev/kmsg"
log_con_path="/dev/tty1"

# 定义日志格式-前缀
log_prefix="[setup-environment]"
# 定义日志目录和文件名
if [ "$user" == "root" ]; then
  log_file_dir="/var/log/kpc/huangdi"
else
  log_file_dir=~/.local/log/kpc/huangdi
fi
log_file_name="firstboot.log"
log_file_path="$log_file_dir/$log_file_name"

function log_init()
{
  # 文件不存在则创建
  if [ ! -d "$log_file_dir" ]; then
    mkdir -p $log_file_dir
    chmod -R 755 $log_file_dir
  fi
  if [ ! -f "$log_file_path" ]; then
    touch $log_file_path
  fi
}

# 定义日志打印格式
function log()
{
  # 定义日志时间格式
  local curtime=$(date "+%Y-%m-%d %H:%M:%S")
  echo "$curtime $log_prefix $@"
  echo "$curtime $log_prefix $@" >> $log_file_path
  #sleep 1
  if [ "$user" == "root" ]; then
    echo "$log_prefix [kmsg] $@" > $log_kmsg_path
    sleep 1
    #echo "$curtime $log_prefix [con] $@" > $log_con_path
    #sleep 1
  fi
}

function log_from_file()
{
  tmpfile=$@
  if [ ! -f "$tmpfile" ]; then
    log "no file [$tmpfile] to log"
    return 1
  fi

  declare_i_arr lists
  while IFS= read -r line;
  do
    add_i_arr_el lists "$line"
  done <$tmpfile

  # 定义日志时间格式
  local curtime=$(date "+%Y-%m-%d %H:%M:%S")

  #echo "$curtime $log_prefix $@"
  #echo "$curtime $log_prefix $@" >>$log_file_path
  local i=0
  get_i_arr_indices lists indices
  for i in $indices
  do
    echo "$curtime $log_prefix ${line}"
    echo "$curtime $log_prefix ${line}" >>$log_file_path
  done

  if [ "$user" == "root" ]; then
    #echo "$log_prefix [kmsg] $@" >$log_kmsg_path
    get_i_arr_indices lists indices
    for i in $indices
    do
      echo "$curtime $log_prefix ${line}" >$log_kmsg_path
      [ $(( i%10 )) -ne 9 ] || sleep 1
    done

    #sleep 1
    #echo "$curtime $log_prefix [con] $@" >$log_con_path
    #for i in $( seq 0 $((${#lists[*]} - 1)) )
    #do
    #  echo "$curtime $log_prefix ${lists[i]}" >$log_con_path
    #done

    #sleep 1
  fi
}

# get Work Dir
function get_work_dir()
{
  ################
  # /etc/kpc/firstboot/guest/huangdi-setup-environment.sh
  # /etc/kpc/firstboot/guest/huangdi-first-boot.sh
  # /etc/kpc/firstboot/root/etc/rc.local
  # /etc/rc.local
  # /kpcos/distro/huangdi/releases/1.04/targets/x86/64/guest/huangdi-setup-environment.sh
  # /kpcos/distro/huangdi/releases/1.04/targets/x86/64/root/etc/rc.local
  ################

  local real_path=$(realpath $0)
  GLB_REAL_PATH="$real_path"
  log "REAL PATH is [$GLB_REAL_PATH]"

  GLB_WORK_DIR=$(dirname "$real_path")
  log "WORK DIR is [$GLB_WORK_DIR]"

  local done_file="${real_path}_done"
  log "done_file=[$done_file]"
  real_done_file=$(realpath "$done_file")
  log "real_done_file=[$real_done_file]"

  GLB_DONE_FILE="$real_done_file"
  log "GLB_DONE_FILE=[$GLB_DONE_FILE]"

  GLB_REBOOT_COUNTER=$GLB_WORK_DIR/reboot_counter
  log "GLB_REBOOT_COUNTER=$GLB_REBOOT_COUNTER"
  if [ ! -f $GLB_REBOOT_COUNTER ]; then
    echo "0" >$GLB_REBOOT_COUNTER
  fi
}

# loop forever to reboot
function force_reboot()
{
  log "force reboot now!"
  while true; do reboot; sleep 9; done
}

function check_reboot_counter()
{
  local reboot_counter=$(cat $GLB_REBOOT_COUNTER)
  reboot_counter=$((reboot_counter + 1))
  log "reboot counter is [$reboot_counter]"
  if [ $reboot_counter -gt 9 ]; then
    log "reboot too many times, exit now!"
    exit 1
  else
    log "set reboot counter to [$reboot_counter]"
    echo "$reboot_counter" >$GLB_REBOOT_COUNTER
  fi
}

function reset_reboot_counter()
{
  log "reset reboot counter"
  echo "0" >$GLB_REBOOT_COUNTER
}

# save installed packages list
function save_pkg_list()
{
  if [ "$1" == "" ]; then
    log "save_pkg_list() filename is empty, do nothing!"
    return
  fi
  local list_file="$PWD"/$1
  log "save $inst_type packages list to $list_file"
  [ -f $list_file ] || opkg list-installed >$list_file
}

# start kpc-heartbeat
function start_heartbeat()
{
  heartbeat_conf_dir=/etc/kpc
  heartbeat_conf_file=/etc/kpc/heartbeat.conf
  heartbeat_file=/usr/sbin/kpc-heartbeat.sh
  heartbeat_lock=/tmp/kpc-hearbeat.lock
  if [ ! -f $heartbeat_conf_file ]; then
    mkdir -p $heartbeat_conf_dir
    echo 9 >$heartbeat_conf_file
  fi
  if [ -x $heartbeat_file ]; then
    log "start kpc-heartbeat"
    (flock -n $heartbeat_lock -c "($heartbeat_file)")&
  fi
}

# run bootstrap configurating
function run_bootstrap_config()
{
  local wifi_backend=""
  local wifi_dev=""
  local wifi_addr=""
  local wifi_mode=""
  local wifi_net=""
  local wifi_pass=""

  local conf_file=/etc/kpc/bootstrap.conf
  if [ -f $conf_file ]; then
    log "start to configurate bootstrap environment"

    declare_i_arr lists
    while IFS= read -r line;
    do
      add_i_arr_el lists "$line"
    done <$conf_file

    local i=0
    get_i_arr_indices lists indices
    for i in $indices
    do
      get_i_arr_val lists $i line
      #log "lists[$i]=[${line}]"
      local name=$(echo ${line} | awk '{print $1}')
      local val=$(echo ${line} | awk '{print $2}')
      #log "name=[$name] val=[$val]"
      case "$name" in
        "#"* )
          #log "it's comment"
          ;;
        "" )
          #log "it's empty line"
          ;;
        "wifi.backend" )
          if [ "$val" == "iwd" ]; then
            log "enable iwd network configuration"
            wifi_backend="$val"
            iwd_main_conf=/etc/iwd/main.conf
            sed "s/#EnableNetworkConfiguration=true/EnableNetworkConfiguration=true/g" -i $iwd_main_conf
            #log_from_file $iwd_main_conf
          fi
          ;;
        "wifi.device_name" )
          wifi_dev="$val"
          log "wifi_dev=[$wifi_dev]"
          ;;
        "wifi.device_address" )
          wifi_addr="$val"
          log "wifi_addr=[$wifi_addr]"
          ;;
        "wifi.mode" )
          wifi_mode="$val"
          log "wifi_mode=[$wifi_mode]"
          ;;
        "wifi.network" )
          wifi_net="$val"
          log "wifi_net=[$wifi_net]"
          ;;
        "wifi.passphrase" )
          wifi_pass="$val"
          log "wifi_pass=[$wifi_pass]"
          ;;
        * )
          log "unknown option=[$name]"
          ;;
      esac
    done
  fi
}

# check WAN interface
function check_wan_iface()
{
  local COUNTER=0
  local dev_array="$(ip route | awk '/default/ {print $5}')"
  local iface_dev=$(echo $dev_array | awk '{print $1}')
  while [ "$iface_dev"x == x ]; do
    sleep 1
    COUNTER=$((COUNTER + 1))
    if [ $COUNTER -gt 29 ]; then
      log "Can't get default route device interface, exit now"
      exit 1
    fi
    dev_array="$(ip route | awk '/default/ {print $5}')"
    iface_dev=$(echo $dev_array | awk '{print $1}')
  done

  COUNTER=0
  local WAN_IP=$(ip addr show $iface_dev | grep "inet" | head -n 1 | awk '/inet/ {print $2}' | cut -d'/' -f1)
  while [ "${WAN_IP}"x == x ]; do
    sleep 1
    COUNTER=$((COUNTER + 1))
    if [ $COUNTER -gt 29 ]; then
      log "Can't get WAN IP address, reboot now"
      force_reboot
    fi
    WAN_IP=$(ip addr show $iface_dev | grep "inet" | head -n 1 | awk '/inet/ {print $2}' | cut -d'/' -f1)
  done
  log "WAN IP=[${WAN_IP}]"
}

# check WAN interface
function ubus_check_wan_iface()
{
  local COUNTER=0
  WAN_IP=$(ubus call network.interface.wan status | grep "address" | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
  while [ "${WAN_IP}"x == x ]; do
    sleep 1
    COUNTER=$((COUNTER + 1))
    if [ $COUNTER -gt 29 ]; then
      log "Can't get WAN IP address, reboot now"
      force_reboot
    fi
    WAN_IP=$(ubus call network.interface.wan status | grep "address" | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
  done
  log "WAN IP=[${WAN_IP}]"
}

# get ROOT device from /proc/self/mountinfo
function simple_get_root_dev()
{
  ROOT_BLK="$(readlink -f /sys/dev/block/"$(awk -e \
    '$9=="/dev/root"{print $3}' /proc/self/mountinfo)")"
  GLB_ROOT_DISK="/dev/$(basename "${ROOT_BLK%/*}")"
  GLB_ROOT_PART="/dev/${ROOT_BLK##*/}"
  GLB_ROOT_PART_NUM="${ROOT_BLK##*[^0-9]}"
  GLB_ROOT_DEV="$GLB_ROOT_DISK"
  #GLB_ROOT_PART="${GLB_ROOT_DEV}${GLB_ROOT_PART_NUM}"
  log "GLB_ROOT_DEV=[$GLB_ROOT_DEV]"
  log "GLB_ROOT_PART=[$GLB_ROOT_PART]"
  log "GLB_ROOT_DISK=[$GLB_ROOT_DISK]"
  log "GLB_ROOT_PART_NUM=[$GLB_ROOT_PART_NUM]"
}

# simple resize root partition
function simple_resize_root_partition()
{
  if [ ! -e /etc/rootpt-resize ] \
  && type parted > /dev/null \
  && lock -n /var/lock/root-resize ; then
    if [ x"$GLB_ROOT_DISK" == x ]; then
      log "detect ROOT_DISK device"
      COUNTER=0
      simple_get_root_dev
      while [ "$GLB_ROOT_DISK"x == x ]; do
        sleep 1
        COUNTER=$((COUNTER + 1))
        if [ $COUNTER -gt 29 ]; then
          log "Can't find ROOT_DISK , reboot now"
          force_reboot
        fi
        log "detect ROOT_DISK again"
        simple_get_root_dev
      done
      log "GLB_ROOT_DISK=[$GLB_ROOT_DISK]"
    fi

    if [ x"$GLB_ROOT_DISK" == x ]; then
      log "GLB_ROOT_DISK=[$GLB_ROOT_DISK] is empty, exit now"
      rm -f /var/lock/root-resize
      exit 1
    fi

    # enlarge partition
    log "expand root partition size to full disk device"
    parted -f -s "${GLB_ROOT_DISK}" resizepart "${GLB_ROOT_PART_NUM}" 100%
    sleep 1
    tmpfile=$(mktemp)
    parted "${GLB_ROOT_DISK}" unit MiB print 2>&1 | tee $tmpfile
    log_from_file $tmpfile
    rm -f $tmpfile
    mount_root done
    touch /etc/rootpt-resize
    log "finish expanding root partition size, reboot now"
    force_reboot
  fi
}

opkg_install_pkg()
{
  PKG_NAME=$1
  log "opkg install $PKG_NAME"

  if [ "${PKG_NAME}"x == x ]; then
    log "Error: PKG_NAME is empty!!!"
    force_reboot
  fi

  opkg install $PKG_NAME 2>&1 | tee /dev/kmsg

  let COUNTER=0
  PKG_INSTALLED=$(opkg list-installed | grep "^$PKG_NAME -" | awk '{print $1}')
  while [ "${PKG_INSTALLED}"x != "${PKG_NAME}"x ]; do
    log "Try to install $PKG_NAME again"
    sleep 1
    let COUNTER=$COUNTER+1
    if [ $COUNTER -gt 29 ]; then
      log "Can't install $PKG_NAME , reboot now"
      force_reboot
    fi
    opkg update 2>&1 | tee /dev/kmsg
    opkg install $PKG_NAME 2>&1 | tee /dev/kmsg
    PKG_INSTALLED=$(opkg list-installed | grep "^$PKG_NAME -" | awk '{print $1}')
  done
}

opkg_remove_force_depends_pkg()
{
  PKG_NAME=$1
  log "opkg remove --force-depends $PKG_NAME"

  if [ "${PKG_NAME}"x == x ]; then
    log "Error: PKG_NAME is empty!!!"
    force_reboot
  fi

  opkg remove --force-depends $PKG_NAME 2>&1 | tee /dev/kmsg

  let COUNTER=0
  PKG_REMOVED=$(opkg list-installed | grep "^$PKG_NAME -" | awk '{print $1}')
  while [ "$PKG_REMOVED"x == "$PKG_NAME"x ]; do
    log "Try to remove $PKG_NAME again"
    sleep 1
    let COUNTER=$COUNTER+1
    if [ $COUNTER -gt 29 ]; then
      log "Can't remove $PKG_NAME , reboot now"
      force_reboot
    fi
    opkg remove --force-depends $PKG_NAME 2>&1 | tee /dev/kmsg
    PKG_REMOVED=$(opkg list-installed | grep "^$PKG_NAME -" | awk '{print $1}')
  done
}

# 0. init script
log_init
log "[setup-environment] START"
get_work_dir
if [ -f $GLB_DONE_FILE ]; then
  log "exist file $GLB_DONE_FILE , exit now"
  exit 1
fi
cd "$GLB_WORK_DIR"
check_reboot_counter
start_heartbeat
run_bootstrap_config
#check_wan_iface
ubus_check_wan_iface
save_pkg_list pre_setup_environment_pkgs.txt

log "PATH=[$PATH]"

# 1. setup WAN interface
uci set network.wan=interface
uci set network.wan.device=eth0
uci set network.wan.proto=dhcp
uci commit

# 2. setup device bridge br-lan ports
uci delete network.@device[0].ports
uci add_list network.@device[0].ports=dummy0
uci commit

# 3. restart network service
service network restart
sleep 1

#check_wan_iface
ubus_check_wan_iface

#opkg remove --force-depends uhttpd
#opkg remove --force-depends dnsmasq
opkg_remove_force_depends_pkg uhttpd
opkg_remove_force_depends_pkg dnsmasq

# 4. install kmod-dummy
if [ ! -f /etc/opkg/distfeeds.conf.ow ]; then
  cp -f /etc/opkg/distfeeds.conf /etc/opkg/distfeeds.conf.ow
fi
sed "s#downloads.openwrt.org#mirrors.aliyun.com/openwrt#g" -i /etc/opkg/distfeeds.conf
opkg update 2>&1 | tee /dev/kmsg
#opkg install kmod-dummy 2>&1 | tee /dev/kmsg
opkg_install_pkg kmod-dummy

# 5. install tools for enlarging partition size
log "install tools for manipulating partition"
#apt-get install -y parted 2>&1
opkg_install_pkg parted

# 6. resize root partition
simple_resize_root_partition

save_pkg_list post_setup_environment_pkgs.txt
touch $GLB_DONE_FILE
sync
#sleep 1

log "[setup-environment] EXIT"
#sleep 1

# restart system
reset_reboot_counter
#poweroff
